{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "d3c1a297-c1a2-425d-bec0-cb358c9b1478",
   "metadata": {},
   "source": [
    "# 实验8 基于全连接深度神经网络模型的手写识别"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5c6d6fac-a5ef-4510-9f03-998142d6131f",
   "metadata": {},
   "source": [
    "### 数据读取"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "06b40d4b-5745-4dcd-821b-a9a866eb61b1",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test set size: 10000\n",
      "Training set size: 60000\n",
      "Number of training samples: 48780\n",
      "Number of cross-validation samples: 5430\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "import torchvision\n",
    "import torchvision.transforms as transforms\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "label_size = 18 # Label size\n",
    "ticklabel_size = 14 # Tick label size\n",
    "\n",
    "class FlattenTransform:\n",
    "    def __call__(self, tensor):\n",
    "        ''' \n",
    "        Flatten tensor into an 1-D vector\n",
    "        '''\n",
    "        return tensor.view(-1)\n",
    "    \n",
    "# Define a transform to normalize the data\n",
    "transform = transforms.Compose([\n",
    "    transforms.ToTensor(),\n",
    "    FlattenTransform()\n",
    "])\n",
    "\n",
    "# Load test data from the MNIST\n",
    "testset = torchvision.datasets.MNIST(root='./Data', train=False, download=False, transform=transform)\n",
    "print(f\"Test set size: {len(testset)}\")\n",
    "\n",
    "# Load training data from the MNIST\n",
    "trainset = torchvision.datasets.MNIST(root='./Data', train=True, download=False, transform=transform)\n",
    "print(f\"Training set size: {len(trainset)}\")\n",
    "\n",
    "# Rate of trX and cvX\n",
    "tr_cv_rate = 0.9\n",
    "\n",
    "# Create a list to store indices for each class\n",
    "class_indices = [[] for _ in range(10)]  # 10 classes in MNIST\n",
    "\n",
    "# Populate class_indices\n",
    "for idx, (_, label) in enumerate(trainset):\n",
    "    class_indices[label].append(idx)\n",
    "\n",
    "# Calculate the number of samples for each class in training and validation sets\n",
    "train_size_per_class = int(tr_cv_rate * min(len(indices) for indices in class_indices))\n",
    "val_size_per_class = min(len(indices) for indices in class_indices) - train_size_per_class\n",
    "\n",
    "# Create balanced train and validation sets\n",
    "train_indices = []\n",
    "val_indices = []\n",
    "for indices in class_indices:\n",
    "    train_indices.extend(indices[:train_size_per_class])\n",
    "    val_indices.extend(indices[train_size_per_class:train_size_per_class + val_size_per_class])\n",
    "\n",
    "# Create Subset datasets\n",
    "from torch.utils.data import Subset\n",
    "trX = Subset(trainset, train_indices)\n",
    "cvX = Subset(trainset, val_indices)\n",
    "\n",
    "print(f\"Number of training samples: {len(trX)}\")\n",
    "print(f\"Number of cross-validation samples: {len(cvX)}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "81e99b1e-515a-4a41-af41-67f472ddcbf4",
   "metadata": {},
   "source": [
    "### 构建DataLoaders，准备训练模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "631ed132-57bb-4431-a2e4-0dd8a1de89b2",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Input_size is 784\n",
      "tensor([[0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],\n",
      "        [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],\n",
      "        [0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],\n",
      "        [1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 1., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],\n",
      "        [0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 1., 0., 0., 0., 0.],\n",
      "        [1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],\n",
      "        [1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],\n",
      "        [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],\n",
      "        [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],\n",
      "        [0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],\n",
      "        [0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],\n",
      "        [0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],\n",
      "        [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],\n",
      "        [0., 0., 0., 0., 0., 1., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],\n",
      "        [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],\n",
      "        [0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],\n",
      "        [1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 1., 0., 0., 0., 0.]])\n"
     ]
    }
   ],
   "source": [
    "batch_size = 52 # Define training batch\n",
    "def one_hot_collate(batch):\n",
    "    data = torch.stack([item[0] for item in batch])\n",
    "    labels = torch.tensor([item[1] for item in batch])\n",
    "    one_hot_labels = torch.zeros(labels.size(0), 10)  # 10 classes in MNIST\n",
    "    one_hot_labels.scatter_(1, labels.unsqueeze(1), 1)\n",
    "    return data, one_hot_labels\n",
    "\n",
    "trLoader = torch.utils.data.DataLoader(trX, batch_size=batch_size, shuffle=True, num_workers=0, collate_fn=one_hot_collate)\n",
    "cvLoader = torch.utils.data.DataLoader(cvX, batch_size=batch_size, shuffle=False, num_workers=0, collate_fn=one_hot_collate)\n",
    "teLoader = torch.utils.data.DataLoader(testset, batch_size=batch_size, shuffle=False, num_workers=0, collate_fn=one_hot_collate)\n",
    "\n",
    "# Get a batch of training data\n",
    "dataiter = iter(trLoader)\n",
    "data, labels = next(dataiter)\n",
    "\n",
    "input_size = data[0].numpy().shape[0]\n",
    "print(f'Input_size is {input_size}')\n",
    "print(labels)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4d1b2063-e168-4c44-b488-f601c99513b2",
   "metadata": {},
   "source": [
    "## 定义并训练全连接神经网络"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "66d0e786-85e7-43ca-9b06-c606cc799ff0",
   "metadata": {},
   "source": [
    "### 输入：1-D向量\n",
    "### 输出：手写字母类型的概率分布\n",
    "### 隐藏层：2层\n",
    "### 节点数：100个/层"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "4a9b06dc-2557-46b7-9209-4086b2b26a13",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "FNN(\n",
      "  (fc1): Linear(in_features=784, out_features=10, bias=True)\n",
      "  (relu1): ReLU()\n",
      "  (fc2): Linear(in_features=10, out_features=10, bias=True)\n",
      "  (relu2): ReLU()\n",
      "  (fc3): Linear(in_features=10, out_features=10, bias=True)\n",
      "  (softmax): Softmax(dim=1)\n",
      ")\n"
     ]
    }
   ],
   "source": [
    "import torch.nn as nn\n",
    "\n",
    "class FNN(nn.Module):\n",
    "    def __init__(self, input_size, hidden_size, num_classes):\n",
    "        super(FNN, self).__init__()\n",
    "        self.fc1 = nn.Linear(input_size, hidden_size)\n",
    "        self.relu1 = nn.ReLU()\n",
    "        self.fc2 = nn.Linear(hidden_size, hidden_size)\n",
    "        self.relu2 = nn.ReLU()\n",
    "        self.fc3 = nn.Linear(hidden_size, num_classes)\n",
    "        self.softmax = nn.Softmax(dim=1)\n",
    "    \n",
    "    def forward(self, x):\n",
    "        x = self.fc1(x)\n",
    "        x = self.relu1(x)\n",
    "        x = self.fc2(x)\n",
    "        x = self.relu2(x)\n",
    "        x = self.fc3(x)\n",
    "        out = self.softmax(x)\n",
    "        return out\n",
    "\n",
    "# Define the model parameters\n",
    "hidden_size = 10\n",
    "num_classes = 10  # MNIST has 10 classes (digits 0-9)\n",
    "\n",
    "# Instantiate the model\n",
    "model = FNN(input_size, hidden_size, num_classes)\n",
    "print(model)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "8eb731cf-f406-4edc-b932-1b22c66526f3",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch [1/39], Train Loss: 1.7830, CV Loss: 1.5997\n",
      "Epoch [2/39], Train Loss: 1.5788, CV Loss: 1.5698\n",
      "Epoch [3/39], Train Loss: 1.5615, CV Loss: 1.5616\n",
      "Epoch [4/39], Train Loss: 1.5537, CV Loss: 1.5552\n",
      "Epoch [5/39], Train Loss: 1.5482, CV Loss: 1.5541\n",
      "Epoch [6/39], Train Loss: 1.5448, CV Loss: 1.5515\n",
      "Epoch [7/39], Train Loss: 1.5412, CV Loss: 1.5480\n",
      "Epoch [8/39], Train Loss: 1.5381, CV Loss: 1.5464\n",
      "Epoch [9/39], Train Loss: 1.5357, CV Loss: 1.5458\n",
      "Epoch [10/39], Train Loss: 1.5330, CV Loss: 1.5437\n",
      "Epoch [11/39], Train Loss: 1.5317, CV Loss: 1.5429\n",
      "Epoch [12/39], Train Loss: 1.5304, CV Loss: 1.5420\n",
      "Epoch [13/39], Train Loss: 1.5287, CV Loss: 1.5423\n",
      "Epoch [14/39], Train Loss: 1.5270, CV Loss: 1.5426\n",
      "Epoch [15/39], Train Loss: 1.5260, CV Loss: 1.5421\n",
      "Epoch [16/39], Train Loss: 1.5243, CV Loss: 1.5395\n",
      "Epoch [17/39], Train Loss: 1.5239, CV Loss: 1.5388\n",
      "Epoch [18/39], Train Loss: 1.5228, CV Loss: 1.5420\n",
      "Epoch [19/39], Train Loss: 1.5216, CV Loss: 1.5395\n",
      "Epoch [20/39], Train Loss: 1.5213, CV Loss: 1.5381\n",
      "Epoch [21/39], Train Loss: 1.5205, CV Loss: 1.5384\n",
      "Epoch [22/39], Train Loss: 1.5194, CV Loss: 1.5373\n",
      "Epoch [23/39], Train Loss: 1.5182, CV Loss: 1.5379\n",
      "Epoch [24/39], Train Loss: 1.5184, CV Loss: 1.5368\n",
      "Epoch [25/39], Train Loss: 1.5181, CV Loss: 1.5365\n",
      "Epoch [26/39], Train Loss: 1.5172, CV Loss: 1.5368\n",
      "Epoch [27/39], Train Loss: 1.5161, CV Loss: 1.5367\n",
      "Epoch [28/39], Train Loss: 1.5162, CV Loss: 1.5370\n",
      "Epoch [29/39], Train Loss: 1.5153, CV Loss: 1.5369\n",
      "Epoch [30/39], Train Loss: 1.5148, CV Loss: 1.5360\n",
      "Epoch [31/39], Train Loss: 1.5141, CV Loss: 1.5355\n",
      "Epoch [32/39], Train Loss: 1.5132, CV Loss: 1.5355\n",
      "Epoch [33/39], Train Loss: 1.5136, CV Loss: 1.5346\n",
      "Epoch [34/39], Train Loss: 1.5133, CV Loss: 1.5342\n",
      "Epoch [35/39], Train Loss: 1.5123, CV Loss: 1.5343\n",
      "Epoch [36/39], Train Loss: 1.5120, CV Loss: 1.5360\n",
      "Epoch [37/39], Train Loss: 1.5113, CV Loss: 1.5352\n",
      "Epoch [38/39], Train Loss: 1.5117, CV Loss: 1.5364\n",
      "Epoch [39/39], Train Loss: 1.5109, CV Loss: 1.5366\n"
     ]
    }
   ],
   "source": [
    "# Define loss function and optimizer\n",
    "criterion = nn.CrossEntropyLoss()\n",
    "optimizer = torch.optim.Adam(model.parameters())\n",
    "\n",
    "# Lists to store losses\n",
    "train_losses = []\n",
    "cv_losses = []\n",
    "\n",
    "# Number of epochs\n",
    "num_epochs = 39\n",
    "\n",
    "for epoch in range(num_epochs):\n",
    "    model.train()\n",
    "    batch_losses = []\n",
    "    \n",
    "    for batch_x, batch_y in trLoader:\n",
    "        # Forward pass\n",
    "        outputs = model(batch_x)\n",
    "        loss = criterion(outputs, batch_y)\n",
    "        \n",
    "        # Backward pass and optimize\n",
    "        optimizer.zero_grad()\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "        \n",
    "        batch_losses.append(loss.item())\n",
    "    \n",
    "    # Calculate average training loss for this epoch\n",
    "    avg_train_loss = sum(batch_losses) / len(batch_losses)\n",
    "    train_losses.append(avg_train_loss)\n",
    "    \n",
    "    # Evaluate on cross-validation set\n",
    "    model.eval()\n",
    "    cv_batch_losses = []\n",
    "    with torch.no_grad():\n",
    "        for cv_x, cv_y in cvLoader:\n",
    "            cv_outputs = model(cv_x)\n",
    "            cv_loss = criterion(cv_outputs, cv_y)\n",
    "            cv_batch_losses.append(cv_loss.item())\n",
    "    \n",
    "    avg_cv_loss = sum(cv_batch_losses) / len(cv_batch_losses)\n",
    "    cv_losses.append(avg_cv_loss)\n",
    "    \n",
    "    print(f'Epoch [{epoch+1}/{num_epochs}], Train Loss: {avg_train_loss:.4f}, CV Loss: {avg_cv_loss:.4f}')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e41506bf-0d45-4b1f-b8d4-9fe5f6bcb3b2",
   "metadata": {},
   "source": [
    "### 计算识别精度，展示学习曲线"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "9d285cbe-2a49-4251-be1a-7ea572068817",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy on training set: 95.08%\n",
      "Accuracy on cross-validation set: 92.43%\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1cAAAHUCAYAAADWedKvAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAB2zklEQVR4nO3dd3hUZcLG4efMTGYyaZOEkoQWQJqgIF1wpQgqoCwoCjYExXVVbIu6LjZwLdjFip9rwbaIirDuqgiIiAoKqMGGCNICBFEgvc+c748pyZAAAZJMZvjd13WuOXPavHNyonl4m2GapikAAAAAwFGxhLoAAAAAABAJCFcAAAAAUAsIVwAAAABQCwhXAAAAAFALCFcAAAAAUAsIVwAAAABQCwhXAAAAAFALCFcAAAAAUAsIVwAAAABQCwhXAI4ZhmHUaFm2bNlRfc706dNlGMYRnbts2bJaKUNDN3HiRLVu3bpGx3o8Hr322msaOnSoGjdurKioKDVt2lRnn322/vvf/8rj8dRtYY/S2rVrZRiG/vGPfxzwmA0bNsgwDF1//fU1vm51z9mgQYM0aNCgQ567ZcsWGYah2bNn1/jz/H766SdNnz5dW7ZsqbLvcH6utc0wDF177bUh+WwA8LOFugAAUF9WrlwZ9P6ee+7RJ598oqVLlwZt79y581F9zhVXXKFhw4Yd0bk9evTQypUrj7oMkaK4uFijR4/WokWLdMEFF2jWrFlKTU3V77//roULF+r888/X3LlzNWrUqFAX9YC6deumnj176tVXX9V9990nq9Va5ZiXX35ZkjRp0qSj+qxnn332qM6viZ9++kl33323Bg0aVCVI3XnnnbrhhhvqvAwA0FARrgAcM04++eSg902aNJHFYqmyfX+FhYWKiYmp8ee0aNFCLVq0OKIyJiQkHLI8x5IpU6boo48+0iuvvKJLL700aN+5556rW265RUVFRQc8v6ysTIZhyGYL7f/uJk2apGuuuUYffvihzj777KB9brdbr776qnr27Klu3bod1eeEOpQfd9xxIf18AAg1mgUCQCWDBg3SCSecoOXLl6t///6KiYnR5ZdfLkmaO3euzjjjDKWlpcnpdOr444/XP/7xDxUUFARdo7rmWq1bt9bZZ5+thQsXqkePHnI6nerUqZNeeumloOOqaxY4ceJExcXFaePGjRoxYoTi4uLUsmVL3XTTTSopKQk6f/v27TrvvPMUHx+vxMREXXzxxVq9enWNmoD9/vvvuuaaa9S5c2fFxcWpadOmOu200/TZZ58FHedvUvbII4/oscceU5s2bRQXF6d+/frpyy+/rHLd2bNnq2PHjnI4HDr++OP16quvHrQcfrt27dILL7ygM888s0qw8mvfvr26du0qqeLevfbaa7rpppvUvHlzORwObdy4UZL00ksvqVu3boqOjlZycrLOOeccrVu3Luh6mzZt0gUXXKBmzZrJ4XAoJSVFQ4YMUUZGRuCYpUuXatCgQWrUqJGcTqdatWqlMWPGqLCw8IDf5aKLLpLT6QzUUFW2aNEi7dix47Cfs+pU1yxw586dGjt2rOLj4+VyuTRu3Djt2rWryrlr1qzRBRdcoNatW8vpdKp169a68MILtXXr1sAxs2fP1vnnny9JGjx4cKAprf/Zqq5ZYHFxsaZOnao2bdrIbrerefPmmjx5srKzs4OOq+nvyNHYu3evrrnmGjVv3lx2u11t27bV7bffXuX36O2331bfvn3lcrkUExOjtm3bBn4+krep6r333quOHTvK6XQqMTFRXbt21RNPPFFrZQUQnqi5AoD9ZGVl6ZJLLtHf//533X///bJYvP8OtWHDBo0YMUI33nijYmNj9fPPP+vBBx/UqlWrqjQtrM7atWt100036R//+IdSUlL0wgsvaNKkSWrXrp0GDBhw0HPLysr05z//WZMmTdJNN92k5cuX65577pHL5dJdd90lSSooKNDgwYO1d+9ePfjgg2rXrp0WLlyocePG1eh77927V5I0bdo0paamKj8/X/Pnz9egQYP08ccfV/mj/ZlnnlGnTp00c+ZMSd4mYSNGjNDmzZvlcrkkef8Yv+yyyzRq1Cg9+uijysnJ0fTp01VSUhK4rwfyySefqKysTKNHj65R+f2mTp2qfv366bnnnpPFYlHTpk01Y8YM3Xbbbbrwwgs1Y8YM7dmzR9OnT1e/fv20evVqtW/fXpI0YsQIud1uPfTQQ2rVqpX++OMPrVixIhAEtmzZorPOOkunnnqqXnrpJSUmJmrHjh1auHChSktLD1jD6XK5NGbMGM2dO1e///67mjRpEtj38ssvKzo6WhdddJGko3/OKisqKtLQoUO1c+dOzZgxQx06dND7779f7TOxZcsWdezYURdccIGSk5OVlZWlWbNmqXfv3vrpp5/UuHFjnXXWWbr//vt122236ZlnnlGPHj0kHbjGyjRNjR49Wh9//LGmTp2qU089Vd99952mTZumlStXauXKlXI4HIHjj+Z35FCKi4s1ePBg/frrr7r77rvVtWtXffbZZ5oxY4YyMjL0/vvvS/I2Hx43bpzGjRun6dOnKzo6Wlu3bg269w899JCmT5+uO+64QwMGDFBZWZl+/vnnKoERwDHIBIBj1IQJE8zY2NigbQMHDjQlmR9//PFBz/V4PGZZWZn56aefmpLMtWvXBvZNmzbN3P8/r+np6WZ0dLS5devWwLaioiIzOTnZ/Otf/xrY9sknn5iSzE8++SSonJLMt956K+iaI0aMMDt27Bh4/8wzz5iSzA8//DDouL/+9a+mJPPll18+6HfaX3l5uVlWVmYOGTLEPOeccwLbN2/ebEoyTzzxRLO8vDywfdWqVaYkc86cOaZpmqbb7TabNWtm9ujRw/R4PIHjtmzZYkZFRZnp6ekH/fwHHnjAlGQuXLiwRuX137sBAwYEbd+3b5/pdDrNESNGBG3ftm2b6XA4zIsuusg0TdP8448/TEnmzJkzD/gZ77zzjinJzMjIqFGZqivfY489Fti2Z88e0+FwmBdffHG15xzuczZw4EBz4MCBgfezZs0yJZn/+c9/go77y1/+cshnory83MzPzzdjY2PNJ554IrD97bffrvKM+k2YMCHo57pw4UJTkvnQQw8FHTd37lxTkvn8888HttX0d+RAJJmTJ08+4P7nnnuu2t+jBx980JRkLlq0yDRN03zkkUdMSWZ2dvYBr3X22WebJ5100iHLBODYQ7NAANhPUlKSTjvttCrbN23apIsuukipqamyWq2KiorSwIEDJalK87LqnHTSSWrVqlXgfXR0tDp06BDU7OpADMPQyJEjg7Z17do16NxPP/1U8fHxVQbTuPDCCw95fb/nnntOPXr0UHR0tGw2m6KiovTxxx9X+/3OOuusoMEZ/M3z/GVav369du7cqYsuuiiomWR6err69+9f4zIdrjFjxgS9X7lypYqKijRx4sSg7S1bttRpp52mjz/+WJKUnJys4447Tg8//LAee+wxffvtt1VGIjzppJNkt9t15ZVX6pVXXtGmTZuqfL7b7VZ5eXlg8V9j4MCBOu6444KaBr7xxhsqKSkJanJ2tM9ZZZ988oni4+P15z//OWi7v5assvz8fN16661q166dbDabbDab4uLiVFBQcNif6+ev7dn/3p9//vmKjY0N3Hu/o/kdqUlZYmNjdd555wVt95fNX5bevXtLksaOHau33npLO3bsqHKtPn36aO3atbrmmmv00UcfKTc396jLByAyEK4AYD9paWlVtuXn5+vUU0/VV199pXvvvVfLli3T6tWr9e6770rSQQdV8GvUqFGVbQ6Ho0bnxsTEKDo6usq5xcXFgfd79uxRSkpKlXOr21adxx57TFdffbX69u2refPm6csvv9Tq1as1bNiwasu4//fxN+/yH7tnzx5JUmpqapVzq9u2P/8f2Zs3b65R+f32//n5y1Hdz7VZs2aB/YZh6OOPP9aZZ56phx56SD169FCTJk10/fXXKy8vT5K3+duSJUvUtGlTTZ48Wccdd5yOO+64oL42Q4YMUVRUVGDxByfDMHT55Zfr+++/15o1ayR5mwS2adNGgwcPllQ7z9n+3726n3919/+iiy7S008/rSuuuEIfffSRVq1apdWrV6tJkyaH/bmVP99mswU1g5S89yI1NTVw7/2O5nekJmVJTU2t0h+yadOmstlsgbIMGDBACxYsUHl5uS699FK1aNFCJ5xwgubMmRM4Z+rUqXrkkUf05Zdfavjw4WrUqJGGDBkS+LkCOHbR5woA9lPdHFVLly7Vzp07tWzZskAtgqQG1ceiUaNGWrVqVZXt1Q1eUJ3XX39dgwYN0qxZs4K2+4PFkZTnQJ9fkzINHjxYUVFRWrBgga666qoaf+7+Pz9/ObKysqocu3PnTjVu3DjwPj09XS+++KIk6ZdfftFbb72l6dOnq7S0VM8995wk6dRTT9Wpp54qt9utNWvW6KmnntKNN96olJQUXXDBBfq///u/oHtW+foTJ07UXXfdpZdeeklRUVH69ttvdc899wTKXNvPWU2fiZycHP3vf//TtGnTgubjKikpCfTFO9LPLy8vr9LPzDRN7dq1K1BLVB8aNWqkr776SqZpBj0ju3fvVnl5edDPadSoURo1apRKSkr05ZdfasaMGbrooovUunVr9evXTzabTVOmTNGUKVOUnZ2tJUuW6LbbbtOZZ56pzMzMwxpdFEBkoeYKAGrA/8dY5c73kvR///d/oShOtQYOHKi8vDx9+OGHQdvffPPNGp1vGEaV7/fdd99VmR+spjp27Ki0tDTNmTNHpmkGtm/dulUrVqw45PmpqamBWpQDjTD466+/6rvvvjvodfr16yen06nXX389aPv27du1dOlSDRkypNrzOnTooDvuuEMnnniivvnmmyr7rVar+vbtq2eeeUaSAsd07NhRvXr1CiyVR89r1qyZhg0bpjlz5uiZZ56RxWLRhAkTAvtr+zkbPHiw8vLy9N577wVt//e//x303jAMmaZZ5XNfeOEFud3uoG3711AejP/e7n/v582bp4KCggPe+7owZMgQ5efna8GCBUHb/c9WdWVxOBwaOHCgHnzwQUnSt99+W+WYxMREnXfeeZo8ebL27t1b7eTKAI4d1FwBQA30799fSUlJuuqqqzRt2jRFRUXpjTfe0Nq1a0NdtIAJEybo8ccf1yWXXKJ7771X7dq104cffqiPPvpIkg45Ot/ZZ5+te+65R9OmTdPAgQO1fv16/fOf/1SbNm1UXl5+2OWxWCy65557dMUVV+icc87RX/7yF2VnZ2v69Ok1ahYoeZsqbtq0SRMnTtRHH32kc845RykpKfrjjz+0ePFivfzyy3rzzTcD/b2qk5iYqDvvvFO33XabLr30Ul144YXas2eP7r77bkVHR2vatGmSvEHy2muv1fnnn6/27dvLbrdr6dKl+u677wK1Oc8995yWLl2qs846S61atVJxcXFgqPChQ4fW6DtNmjRJ77//fmCY+ZYtWwb21fZzdumll+rxxx/XpZdeqvvuu0/t27fXBx98EHgm/BISEjRgwAA9/PDDaty4sVq3bq1PP/1UL774ohITE4OOPeGEEyRJzz//vOLj4xUdHa02bdpU26Tv9NNP15lnnqlbb71Vubm5OuWUUwKjBXbv3l3jx48/ou91IL/++qveeeedKts7d+6sSy+9VM8884wmTJigLVu26MQTT9Tnn3+u+++/XyNGjAj8/O666y5t375dQ4YMUYsWLZSdna0nnngiqO/byJEjdcIJJ6hXr15q0qSJtm7dqpkzZyo9PT0w8iSAY1Rox9MAgNA50GiBXbp0qfb4FStWmP369TNjYmLMJk2amFdccYX5zTffVBl17UCjBZ511llVrrn/6G4HGi1w/3Ie6HO2bdtmnnvuuWZcXJwZHx9vjhkzxvzggw+qHTFufyUlJebNN99sNm/e3IyOjjZ79OhhLliwoMoIcP7RAh9++OEq15BkTps2LWjbCy+8YLZv39602+1mhw4dzJdeeqnKNQ+mvLzcfOWVV8zTTjvNTE5ONm02m9mkSRNz+PDh5r///W/T7Xabpllx795+++1qr/PCCy+YXbt2Ne12u+lyucxRo0aZP/74Y2D/b7/9Zk6cONHs1KmTGRsba8bFxZldu3Y1H3/88cCoiCtXrjTPOeccMz093XQ4HGajRo3MgQMHmu+9916NvotpmmZpaamZkpJS7ch1pnl0z9n+z5Npmub27dvNMWPGBD0TK1asqHI9/3FJSUlmfHy8OWzYMPOHH34w09PTzQkTJgRdc+bMmWabNm1Mq9UadJ3qfq5FRUXmrbfeaqanp5tRUVFmWlqaefXVV5v79u0LOq6mvyMHIumAi/+Z3LNnj3nVVVeZaWlpps1mM9PT082pU6eaxcXFgev873//M4cPH242b97ctNvtZtOmTc0RI0aYn332WeCYRx991Ozfv7/ZuHFj0263m61atTInTZpkbtmy5ZDlBBDZDNOs1FYDABBx7r//ft1xxx3atm2bWrRoEeriAAAQsWgWCAAR5Omnn5YkderUSWVlZVq6dKmefPJJXXLJJQQrAADqGOEKACJITEyMHn/8cW3ZskUlJSVq1aqVbr31Vt1xxx2hLhoAABGPZoEAAAAAUAsYih0AAAAAagHhCgAAAABqAeEKAAAAAGoBA1pUw+PxaOfOnYqPj5dhGKEuDgAAAIAQMU1TeXl5atasmSyWg9dNEa6qsXPnTrVs2TLUxQAAAADQQGRmZh5yWhPCVTXi4+MleW9gQkJCiEsDAAAAIFRyc3PVsmXLQEY4GMJVNfxNARMSEghXAAAAAGrUXYgBLQAAAACgFhCuAAAAAKAWEK4AAAAAoBbQ5woAAOAYZ5qmysvL5Xa7Q10UICSioqJktVqP+jqEKwAAgGNYaWmpsrKyVFhYGOqiACFjGIZatGihuLi4o7oO4QoAAOAY5fF4tHnzZlmtVjVr1kx2u71GI6IBkcQ0Tf3+++/avn272rdvf1Q1WIQrAACAY1Rpaak8Ho9atmypmJiYUBcHCJkmTZpoy5YtKisrO6pwxYAWAAAAxziLhT8JcWyrrRpbfpMAAAAAoBYQrgAAAACgFhCuAAAAcMwbNGiQbrzxxhofv2XLFhmGoYyMjDorE8IP4QoAAABhwzCMgy4TJ048ouu+++67uueee2p8fMuWLZWVlaUTTjjhiD6vpghx4YXRAgEAABA2srKyAutz587VXXfdpfXr1we2OZ3OoOPLysoUFRV1yOsmJycfVjmsVqtSU1MP6xxEPmquGrgXPtukMx9frhc+2xTqogAAgAhnmqYKS8tDspimWaMypqamBhaXyyXDMALvi4uLlZiYqLfeekuDBg1SdHS0Xn/9de3Zs0cXXnihWrRooZiYGJ144omaM2dO0HX3bxbYunVr3X///br88ssVHx+vVq1a6fnnnw/s379GadmyZTIMQx9//LF69eqlmJgY9e/fPyj4SdK9996rpk2bKj4+XldccYX+8Y9/6KSTTjqin5cklZSU6Prrr1fTpk0VHR2tP/3pT1q9enVg/759+3TxxRerSZMmcjqdat++vV5++WVJ3qH4r732WqWlpSk6OlqtW7fWjBkzjrgsoOaqwdtXWKr1v+Vp+76iUBcFAABEuKIytzrf9VFIPvunf56pGHvt/Gl666236tFHH9XLL78sh8Oh4uJi9ezZU7feeqsSEhL0/vvva/z48Wrbtq369u17wOs8+uijuueee3TbbbfpnXfe0dVXX60BAwaoU6dOBzzn9ttv16OPPqomTZroqquu0uWXX64vvvhCkvTGG2/ovvvu07PPPqtTTjlFb775ph599FG1adPmiL/r3//+d82bN0+vvPKK0tPT9dBDD+nMM8/Uxo0blZycrDvvvFM//fSTPvzwQzVu3FgbN25UUZH378onn3xS7733nt566y21atVKmZmZyszMPOKygHDV4CU67ZKk7MLSEJcEAAAgPNx4440699xzg7bdfPPNgfXrrrtOCxcu1Ntvv33QcDVixAhdc801kryB7fHHH9eyZcsOGq7uu+8+DRw4UJL0j3/8Q2eddZaKi4sVHR2tp556SpMmTdJll10mSbrrrru0aNEi5efnH9H3LCgo0KxZszR79mwNHz5ckvSvf/1Lixcv1osvvqhbbrlF27ZtU/fu3dWrVy9J3ho5v23btql9+/b605/+JMMwlJ6efkTlQAXCVQPnivG2Ec4uKgtxSQAAQKRzRln10z/PDNln1xZ/kPBzu9164IEHNHfuXO3YsUMlJSUqKSlRbGzsQa/TtWvXwLq/+eHu3btrfE5aWpokaffu3WrVqpXWr18fCGt+ffr00dKlS2v0vfb366+/qqysTKecckpgW1RUlPr06aN169ZJkq6+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tq369u17yHvh8Xh07rnnqnHjxvryyy+Vm5sb1D/LLz4+XrNnz1azZs30/fff6y9/+Yvi4+P197//XePGjdMPP/yghQsXasmSJZIkl8tV5RqFhYUaNmyYTj75ZK1evVq7d+/WFVdcoWuvvTYoQH7yySdKS0vTJ598oo0bN2rcuHE66aST9Je//OWQ32d/pmlq9OjRio2N1aeffqry8nJdc801GjdunJYtWyZJuvjii9W9e3fNmjVLVqtVGRkZgdrJyZMnq7S0VMuXL1dsbKx++uknxcXFHXY5Dgd/pYeB6CiL7DaLSss9yi4sJVwBAIBj1saNG2Wapjp16lSj4y+66CJdfvnlQe8nTpyoa665RpICtV2PPPKIBg8erG3btik1NVVDhw5VVFSUWrVqpT59+kjy1qLExsbq7LPPVnx8vNLT09W9e/cDfvbll1+uhx9+WMuWLdPgwYMleZsEnnvuuUpKSlJSUpJuvvnmwPHXXXedFi5cqLfffrtG4WrJkiVat26dtmzZohYtWkiS7r///ir9pO64447AeuvWrXXTTTdp7ty5+vvf/y6n06m4uDjZbLaDNgN84403VFRUpFdffTUQap9++mmNHDlSDz74oFJSUiRJSUlJevrpp2W1WtWpUyedddZZ+vjjj48oXC1ZskTfffedNm/erJYtW0qSXnvtNXXp0kWrV69W7969tW3bNt1yyy2B56F9+/aB87dt26YxY8boxBNPlCS1bdv2sMtwuPgrPQwYhqGkmCj9llui7MIytUgKdYkAAEBEiorx1iCF6rNrwN9Fwl8TdCi9evUKer9u3boqA0KccsopeuKJJyRJ559/vmbOnKm2bdtq2LBhGjFihEaOHCmbzabTTz9d6enpgX3Dhg3TOeeco5iYGL3xxhv661//Grjmhx9+qFNPPVX9+/fXSy+9pMGDB+vXX3/VZ599pkWLFkmS3G63HnjgAc2dO1c7duxQSUmJSkpKqq2Rq866devUqlWrQLCSpH79+lU57p133tHMmTO1ceNG5efnq7y8XAkJCTX6jMqf1a1bt6CynXLKKfJ4PFq/fn0gXHXp0kVWqzVwTFpamr7//vvD+qzKn9myZctAsJKkzp07KzExUevWrVPv3r01ZcoUXXHFFXrttdc0dOhQnX/++TruuOMkSddff72uvvpqLVq0SEOHDtWYMWPUtWvXIypLTdHnKkz4mwYyqAUAAKgzhuFtmheKpYZhqX379jIMQ+vWravR8dUFlf2DmWmagW0tW7bU+vXr9cwzz8jpdOqaa67RgAEDVFZWpvj4eH3zzTeaM2eO0tLSdNddd6lbt27Kzs7Wn//8Z2VkZAQWf6ibNGmS5s2bp9zcXL388stKT0/XkCFDJEmPPvqoHn/8cf3973/X0qVLlZGRoTPPPFOlpTUbIbq6vvj7f7cvv/xSF1xwgYYPH67//e9/+vbbb3X77bfX+DOqu0cH+8z9BwwxDEMej+ewPutQn1l5+/Tp0/Xjjz/qrLPO0tKlS9W5c2fNnz9fknTFFVdo06ZNGj9+vL7//nv16tVLTz311BGVpaYIV2HCVWlQCwAAgGNVcnKyzjzzTD3zzDMqKCiosj87O/ug5x9//PH6/PPPg7atWLFCxx9/fOC90+nUn//8Zz355JNatmyZVq5cGah9sdlsGjp0qB566CF999132rJli5YuXar4+Hi1a9cusDidTknS2LFjZbVa9e9//1uvvPKKLrvsskAw+OyzzzRq1Chdcskl6tatm9q2basNGzbU+F507txZ27Zt086dFbWNK1euDDrmiy++UHp6um6//Xb16tVL7du319atW4OOsdvtcrvdh/ysjIyMoHv+xRdfyGKxqEOHDjUu8+Hwf7/MzMzAtp9++kk5OTlBP68OHTrob3/7mxYtWqRzzz1XL7/8cmBfy5YtddVVV+ndd9/VTTfdpH/96191UlY/mgWGiUSnfyJh5roCAADHtmeffVb9+/dXnz599M9//lNdu3ZVeXm5Fi9erFmzZh20VuuWW27R2LFj1aNHDw0ZMkT//e9/9e677wYGc5g9e7bcbrf69u2rmJgYvfbaa3I6nUpPT9f//vc/bdq0SQMGDFBSUpI++OADeTwedezY8YCfFxcXp3Hjxum2225TTk6OJk6cGNjXrl07zZs3TytWrFBSUpIee+wx7dq1Kyg4HMzQoUPVsWNHXXrppXr00UeVm5ur22+/PeiYdu3aadu2bXrzzTfVu3dvvf/++4GaHb/WrVtr8+bNysjIUIsWLRQfHy+HwxF0zMUXX6xp06ZpwoQJmj59un7//Xddd911Gj9+fKBJ4JFyu93KyMgI2ma32zV06FB17dpVF198sWbOnBkY0GLgwIHq1auXioqKdMstt+i8885TmzZttH37dq1evVpjxoyRJN14440aPny4OnTooH379mnp0qU1vrdHipqrMJFIzRUAAIAkqU2bNvrmm280ePBg3XTTTTrhhBN0+umn6+OPP9asWbMOeu7o0aP1xBNP6OGHH1aXLl30f//3f3r55Zc1aNAgSd7RBv/1r3/plFNOUdeuXfXxxx/rv//9rxo1aqTExES9++67Ou2003T88cfrueee05w5c9SlS5eDfuakSZO0b98+DR06VK1atQpsv/POO9WjRw+deeaZGjRokFJTUzV69Oga3weLxaL58+erpKREffr00RVXXKH77rsv6JhRo0bpb3/7m6699lqddNJJWrFihe68886gY8aMGaNhw4Zp8ODBatKkSbXDwcfExOijjz7S3r171bt3b5133nkaMmSInn766RqX90Dy8/PVvXv3oGXEiBGBoeCTkpI0YMAADR06VG3bttXcuXMlSVarVXv27NGll16qDh06aOzYsRo+fLjuvvtuSd7QNnnyZB1//PEaNmyYOnbsqGefffaoy3swhsnESVXk5ubK5XIpJyfnsDv71ZX7P1in55dv0l9ObaPbz+oc6uIAAIAIUFxcrM2bN6tNmzaKjo4OdXGAkDnY78LhZANqrsKEy0nNFQAAANCQEa7CRKBZIKMFAgAAAA0S4SpMBIZip+YKAAAAaJAIV2GiouaK0QIBAACAhohwFSbocwUAAOoK45vhWFdbvwOEqzBRuc8V/wEEAAC1ISrK+/dFYWFhiEsChFZpqbd1mNVqParrMIlwmEiM8fa5Ki33qLjMI6f96H7wAAAAVqtViYmJ2r17tyTvXEaGYYS4VED98ng8+v333xUTEyOb7ejiEeEqTMTarbJZDJV7TGUXlcppd4a6SAAAIAKkpqZKUiBgAccii8WiVq1aHfU/LhCuwoRhGEqMidIf+aXKLixTmotwBQAAjp5hGEpLS1PTpk1VVkbfbhyb7Ha7LJaj7zFFuAojiTH2QLgCAACoTVar9aj7mwDHupAOaLF8+XKNHDlSzZo1k2EYWrBgwUGPnzhxogzDqLJ06dIlcMzs2bOrPaa4uLiOv03dS/SNGJjDcOwAAABAgxPScFVQUKBu3brp6aefrtHxTzzxhLKysgJLZmamkpOTdf755wcdl5CQEHRcVlaWoqOj6+Ir1KvAiIHUXAEAAAANTkibBQ4fPlzDhw+v8fEul0su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X5UkZWdnq2/fvnr00Uc1evRozZo1q1YLWJnH45FhGHrjjTfUp08fjRgxQo899phmz56toqIiSdLJJ5+sSy65RN26ddOpp56qt956Sx06dNBTTz11wOtOnTpVOTk5gSUzM7POvkNdC/S5olkgAAAAUK+OKFx98803OvXUUyVJ77zzjlJSUrR161a9+uqrevLJJ2u1gJWlpaWpefPmcrlcgW3HH3+8TNMMmtS4MovFot69ex+05srhcCghISFoCVeBPlc0CwQAAADq1RGFq8LCQsXHx0uSFi1apHPPPVcWi0Unn3yytm7dWqsFrOyUU07Rzp07lZ+fH9j2yy+/yGKxqEWLFtWeY5qmMjIylJaWVmflakgSY3xDsVNzBQAAANSrIwpX7dq104IFC5SZmamPPvpIZ5xxhiRp9+7dh1Xrk5+fr4yMDGVkZEiSNm/erIyMDG3btk2St7nepZdeGjj+oosuUqNGjXTZZZfpp59+0vLly3XLLbfo8ssvDwxocffdd+ujjz7Spk2blJGRoUmTJikjI0NXXXXVkXzVsJPIUOwAAABASBxRuLrrrrt08803q3Xr1urTp4/69esnyVuLdbBR+fa3Zs0ade/ePXDOlClT1L17d911112SpKysrEDQkqS4uDgtXrxY2dnZ6tWrly6++GKNHDkyqClidna2rrzySh1//PE644wztGPHDi1fvvywhogPZ/5mgTlFZfJ4zBCXBgAAADh2GKZpHtFf4Lt27VJWVpa6desmi8Wb0VatWqWEhAR16tSpVgtZ33Jzc+VyuZSTkxN2/a+Ky9zqdOdCSdLaaWfI5QtbAAAAAA7f4WSDI5rnSpJSU1OVmpqq7du3yzAMNW/e/JipHWrIoqOsckZZVVTmVk5hGeEKAAAAqCdH1CzQ4/Hon//8p1wul9LT09WqVSslJibqnnvukcfjqe0y4jAF+l0V0e8KAAAAqC9HVHN1++2368UXX9QDDzygU045RaZp6osvvtD06dNVXFys++67r7bLicPgckYpK6eY4dgBAACAenRE4eqVV17RCy+8oD//+c+Bbd26dVPz5s11zTXXEK5CLMk3HDsTCQMAAAD154iaBe7du7faQSs6deqkvXv3HnWhcHT8zQJzGI4dAAAAqDdHFK66deump59+usr2p59+Wl27dj3qQuHoVMx1Rc0VAAAAUF+OqFngQw89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zZ07VzfeeKNuv/12ffvttzr11FM1fPhwbdu2LdRFi1hdunRRVlZWYPn+++9DXaSIUlBQoG7duunpp5+udv9DDz2kxx57TE8//bRWr16t1NRUnX766crLy6vnkkaOQ91zSRo2bFjQc//BBx/UYwkjy6effqrJkyfryy+/1OLFi1VeXq4zzjhDBQUFgWN4zmtXTe65xHNeW1q0aKEHHnhAa9as0Zo1a3Taaadp1KhRgT8seb5r36HuucTzXVdWr16t559/Xl27dg3aXm/PuYla1adPH/Oqq64K2tapUyfzH//4R4hKFNmmTZtmduvWLdTFOGZIMufPnx947/F4zNTUVPOBBx4IbCsuLjZdLpf53HPPhaCEkWf/e26apjlhwgRz1KhRISnPsWD37t2mJPPTTz81TZPnvD7sf89Nk+e8riUlJZkvvPACz3c98t9z0+T5rit5eXlm+/btzcWLF5sDBw40b7jhBtM06/e/49Rc1aLS0lJ9/fXXOuOMM4K2n3HGGVqxYkWIShX5NmzYoGbNmqlNmza64IILtGnTplAX6ZixefNm7dq1K+iZdzgcGjhwIM98HVu2bJmaNm2qDh066C9/+Yt2794d6iJFjJycHElScnKyJJ7z+rD/PffjOa99brdbb775pgoKCtSvXz+e73qw/z334/mufZMnT9ZZZ52loUOHBm2vz+fcVqtXO8b98ccfcrvdSklJCdqekpKiXbt2hahUka1v37569dVX1aFDB/3222+699571b9/f/34449q1KhRqIsX8fzPdXXP/NatW0NRpGPC8OHDdf755ys9PV2bN2/WnXfeqdNOO01ff/11vcw+H8lM09SUKVP0pz/9SSeccIIknvO6Vt09l3jOa9v333+vfv36qbi4WHFxcZo/f746d+4c+MOS57v2HeieSzzfdeHNN9/UN998o9WrV1fZV5//HSdc1QHDMILem6ZZZRtqx/DhwwPrJ554ovr166fjjjtOr7zyiqZMmRLCkh1beObr17hx4wLrJ5xwgnr16qX09HS9//77Ovfcc0NYsvB37bXX6rvvvtPnn39eZR/Ped040D3nOa9dHTt2VEZGhrKzszVv3jxNmDBBn376aWA/z3ftO9A979y5M893LcvMzNQNN9ygRYsWKTo6+oDH1cdzTrPAWtS4cWNZrdYqtVS7d++ukpRRN2JjY3XiiSdq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",
      "text/plain": [
       "<Figure size 1000x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import os\n",
    "os.environ['KMP_DUPLICATE_LIB_OK']='True'\n",
    "\n",
    "# Calculate and print accuracies for training and cross-validation sets\n",
    "model.eval()\n",
    "with torch.no_grad():\n",
    "    # Training set accuracy\n",
    "    tr_correct = 0\n",
    "    tr_total = 0\n",
    "    for images, labels in trLoader:\n",
    "        outputs = model(images)\n",
    "        _, predicted = torch.max(outputs, 1)\n",
    "        _, true_labels = torch.max(labels, 1)\n",
    "        tr_total += labels.size(0)\n",
    "        tr_correct += (predicted == true_labels).sum().item()\n",
    "    \n",
    "    tr_accuracy = 100 * tr_correct / tr_total\n",
    "    \n",
    "    # Cross-validation set accuracy\n",
    "    cv_correct = 0\n",
    "    cv_total = 0\n",
    "    for images, labels in cvLoader:\n",
    "        outputs = model(images)\n",
    "        _, predicted = torch.max(outputs, 1)\n",
    "        _, true_labels = torch.max(labels, 1)\n",
    "        cv_total += labels.size(0)\n",
    "        cv_correct += (predicted == true_labels).sum().item()\n",
    "    \n",
    "    cv_accuracy = 100 * cv_correct / cv_total\n",
    "\n",
    "print(f'Accuracy on training set: {tr_accuracy:.2f}%')\n",
    "print(f'Accuracy on cross-validation set: {cv_accuracy:.2f}%')\n",
    "\n",
    "# Plot training and cross-validation losses\n",
    "plt.figure(figsize=(10, 5))\n",
    "plt.plot(range(1, num_epochs+1), train_losses, label='Training Loss')\n",
    "plt.plot(range(1, num_epochs+1), cv_losses, label='Cross-Validation Loss')\n",
    "plt.xlabel('Epoch')\n",
    "plt.ylabel('Loss')\n",
    "plt.title('Training and Cross-Validation Loss')\n",
    "plt.legend()\n",
    "plt.savefig('2.png', dpi=300) # Make figure clearer\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "06d78c5c-2059-410c-b3d9-9258d8e06dd3",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
